package com.aop;

import com.alibaba.fastjson.JSONArray;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
import org.springframework.util.ReflectionUtils;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Objects;

@Component
public class InvokeService implements ApplicationContextAware {

    private static final Logger LOGGER = LoggerFactory.getLogger(InvokeService.class);


    private static final HashMap<String, Class<?>> primClasses
            = new HashMap<>(8, 1.0F);
    static {
        primClasses.put("boolean", boolean.class);
        primClasses.put("byte", byte.class);
        primClasses.put("char", char.class);
        primClasses.put("short", short.class);
        primClasses.put("int", int.class);
        primClasses.put("long", long.class);
        primClasses.put("float", float.class);
        primClasses.put("double", double.class);
    }

    private static final String JOB_THREAD_INVOKING = "jobThreadInvoking";

    @Autowired
    private ApplicationContext applicationContext;

    public static final ThreadLocal<String> THREAD_LOCAL = new ThreadLocal<>();



    /**
     * 异步拉取参数执行
     */
    public void asyncInvoke() {
//        List<RiskControlBizRecord> records = auditAspectDao.getService();
        //查询审批通过 待执行的任务
        ArrayList<RiskControlBizRecord> records = new ArrayList<>();
        if(CollectionUtils.isEmpty(records)){
            return;
        }
        // 2.设置job线程标识，执行时跳过拦截
        THREAD_LOCAL.set(JOB_THREAD_INVOKING);
        for (RiskControlBizRecord data : records) {
            handle(data);
        }
        // 防止内存泄漏
        THREAD_LOCAL.remove();
    }

    private void handle(RiskControlBizRecord serviceObj) {
        try {
            // 修改业务执行状态为已执行
            serviceObj.setBizStatus(RiskControlConstants.BizStatus.AUDITED.getCode());
//            appStoreAuditService.riskControlBizRecordUpdateBizStatus(serviceObj);

            // 3.找方法和参数
            String className = serviceObj.getClassName();
            String methodName = serviceObj.getMethodName();
            Class<?> aClass = Class.forName(className);
            Method methodName1 = aClass.getMethod("methodName");
            Pair<Method, Object[]> pair = getMethod(serviceObj, aClass);
            Method method = pair.getLeft();

            // 4.执行
            ReflectionUtils.makeAccessible(method);
            Object bean = applicationContext.getBean(aClass);
            Object invoke = method.invoke(bean, pair.getValue());

            serviceObj.setBizResult(RiskControlConstants.BizResult.SUCCESS.getCode());
            serviceObj.setBizErrorMsg(Objects.toString(invoke));

            //将任务的结果同步到任务表
//            appStoreAuditService.riskControlBizRecordUpdateBizResult(serviceObj);

            // 邮件提醒
        } catch (Exception e) {
            LOGGER.error("异步拉取参数执行报错："+ serviceObj, e);

            String stackTrace = getStackTrace(e);
            LOGGER.info("InvokeService stackTrace:{}", stackTrace);
            serviceObj.setBizErrorMsg(stackTrace);

            serviceObj.setBizResult(RiskControlConstants.BizResult.FAIL.getCode());
            //更新为失败状态
//            appStoreAuditService.riskControlBizRecordUpdateBizResult(serviceObj);

        }
    }

    public String getStackTrace(Throwable throwable) {
        final Writer result = new StringWriter();
        final PrintWriter printWriter = new PrintWriter(result);
        throwable.printStackTrace(printWriter);
        return result.toString();
    }

    private Pair<Method, Object[]> getMethod(RiskControlBizRecord serviceObj, Class<?> aClass)
            throws ClassNotFoundException, NoSuchMethodException {
        List<ParamObj> paramList = JSONArray.parseArray(serviceObj.getBizData(), ParamObj.class);
        Class[] paramClassArray = null;
        Object[] paramArray = null;
        if (CollectionUtils.isNotEmpty(paramList)) {
            paramClassArray = new Class[paramList.size()];
            paramArray = new Object[paramList.size()];
            for (int i = 0; i < paramList.size(); i++) {
                ParamObj paramObj = paramList.get(i);
                Class<?> paramClass = primClasses.get(paramObj.getClassName());
                if (paramClass == null) {
                    paramClass = Class.forName(paramObj.getClassName());
                }
                paramClassArray[i] = paramClass;
                paramArray[i] = JSONArray.parseObject(paramObj.getJsonValue(), paramClass);
            }
        }

        return Pair.of(aClass.getDeclaredMethod(serviceObj.getMethodName(), paramClassArray), paramArray);
    }

    public boolean isJobThread() {
        return JOB_THREAD_INVOKING.equals(THREAD_LOCAL.get());
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}




